import subprocess as p
from dataclasses import dataclass, is_dataclass
from pathlib import Path
from typing import Any, Literal


def _to_key(name: str) -> str:
    return f'--{name.replace("_", "-")}'


def to_args(opts):
    data: dict[str, Any] = {}
    if is_dataclass(opts):
        data = vars(opts)
    elif isinstance(opts, dict):
        data = opts
    for k, v in data.items():
        key = _to_key(k)
        if isinstance(v, bool):
            yield key
            continue
        if isinstance(v, (Path, int, str)):
            yield f'{key}={v!s}'
            continue
        assert False, (k, v)


@dataclass
class URunnerOptions:
    build_dir: Path
    work_dir: Path
    no_js: bool = True
    processes: int | Literal['all'] = 'all'


class URunner:
    def __init__(self, runner: Path, options: URunnerOptions):
        self.runner = runner
        self.options = options

    def _get_args(self):
        return [
            f'{self.runner!s}',
            *to_args(self.options),
        ]

    def run(self, *args: str, **kwargs):
        cmd = [
            *self._get_args(),
            *args,
            *to_args(kwargs),
        ]
        return p.run(
            args=cmd,
            text=True,
            encoding='utf-8',
            stderr=p.STDOUT,
        )


@dataclass
class AstCheckerOptions:
    astchecker = True
    test_file: Path | None = None


class AstChecker:
    def __init__(self, runner: URunner):
        self.runner = runner

    def run(self, *args: str, test_file: Path | None = None):
        arguments = [*args]
        if test_file:
            arguments.append(f'--test-file={test_file!s}')
        return self.runner.run('--astchecker', *arguments)
